using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;

namespace Ufaev.Cryptography
{
	/// <summary>
	/// Represents the base class from which all implementations of the GOST 28147-89 symmetric encryption algorithm must inherit.
	/// </summary>
	/// <remarks>This algorithm supports a key length of 256 bits.</remarks>
	[ComVisible(true)]
	public abstract class Gost28147 : SymmetricAlgorithm
	{
		#region Static Methods

		/// <summary>
		/// Creates an instance of a cryptographic object to perform the GOST 28147-89 algorithm.
		/// </summary>
		/// <remarks>Creates an instance of the GOST 28147-89 object that can be used for encrypting and decrypting data.</remarks>
		/// <returns>A cryptographic object.</returns>
		public static new Gost28147 Create()
		{
			return Create("Ufaev.Cryptography.Gost28147");
		}

		/// <summary>
		/// Creates an instance of a cryptographic object to perform the specified implementation of the GOST 28147-89 algorithm.
		/// </summary>
		/// <param name="algName">The name of the specific implementation of GOST 28147-89 to use.</param>
		/// <returns>A cryptographic object.</returns>
		public static new Gost28147 Create(string algName)
		{
			return (Gost28147)CryptoConfig.CreateFromName(algName);
		}

		#endregion Static Methods

		#region Properties

		/// <summary>
		/// Gets or sets the secret key for the GOST 28147-89 algorithm.
		/// </summary>
		/// <value>The secret key for the GOST 28147-89 algorithm.</value>
		/// <remarks>
		/// If this property is null (Nothing in Visual Basic) when it is used, <see cref="GenerateKey"/> is called to create a new random value.
		/// The length of the key must be equal to <see cref="BlockSizeValue"/>.
		/// This algorithm supports a key length of 256 bits.
		/// </remarks>
		public override byte[] Key
		{
			get
			{
				if (KeyValue == null)
					GenerateKey();

				return (byte[])KeyValue.Clone();
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("Key");
				if (!this.ValidKeySize(value.Length * 8))
					throw new CryptographicException("Invalid Key Size");

				KeyValue = (byte[])value.Clone();
			}
		}

		#endregion Properties

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="Gost28147"/> class.
		/// </summary>
		protected Gost28147()
		{
			KeySizeValue = 256;
			BlockSizeValue = 64;
			FeedbackSizeValue = 8;

			LegalKeySizesValue = new KeySizes[1];
			LegalKeySizesValue[0] = new KeySizes(256, 256, 0);

			LegalBlockSizesValue = new KeySizes[1];
			LegalBlockSizesValue[0] = new KeySizes(64, 64, 0);
		}

		#endregion Constructors
	}
}
